﻿package com.shuqi.common;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import com.shuqi.common.utils.Log4an;

import android.os.Handler;
import android.os.Message;
import android.os.Process;

public abstract class MyTask implements Runnable {
    private static final int CORE_POOL_SIZE = 8;
    private static final int MAXIMUM_POOL_SIZE = Integer.MAX_VALUE;
    private static final int KEEP_ALIVE = 30;

    private static final BlockingQueue<Runnable> sWorkQueue = new LinkedBlockingQueue<Runnable>(10);

    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
        }
    };
    private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
            MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);

    private static final int MESSAGE_POST_RESULT = 0x1;

    private InternalHandler sHandler;

    private volatile Status mStatus = Status.PENDING;

    public enum Status {
        /**
         * Indicates that the task has not been executed yet.
         */
        PENDING,
        /**
         * Indicates that the task is running.
         */
        RUNNING,
        /**
         * Indicates that {@link MyTask#onPostExecute} has finished.
         */
        FINISHED,
    }

    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    public MyTask() {}

    /**
     * 在后台线程执行
     * 
     * @param run
     * @param isLTimeOper 是否是耗时操作(>1S),是的话请传true
     */
    public static void runInBackground(Runnable run, boolean isLTimeOper) {
        if (isLTimeOper) {
            new Thread(run).start();
        } else {
            sExecutor.execute(run);
        }

        Log4an.d("zyc.mytask", "threadpool size=" + sExecutor.getActiveCount() + ";sWorkQueue="
                + sWorkQueue.size() + ";PoolSize=" + sExecutor.getPoolSize());
    }

    /**
     * Returns the current status of this task.
     * 
     * @return The current status.
     */
    public final Status getStatus() {
        return mStatus;
    }

    protected abstract void doInBackground();

    protected abstract void onPreExecute();

    protected abstract void onPostExecute();

    public void run() {
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        Log4an.d("zyc.MyTask", "before background");

        doInBackground();

        Log4an.d("zyc.MyTask", "after background");
        Message msg = new Message();
        msg.obj = MyTask.this;
        msg.what = MESSAGE_POST_RESULT;
        boolean send = sHandler.sendMessage(msg);

        Log4an.d("zyc.MyTask", "before Handler " + send);
    }

    /**
     * 该方法需要在UI线程执行
     */
    public final void execute() {
        if (mStatus != Status.PENDING) {
            switch (mStatus) {
                case RUNNING:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task is already running.");
                case FINISHED:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task has already been executed "
                            + "(a task can be executed only once)");
            }
        }

        mStatus = Status.RUNNING;
        sHandler = new InternalHandler();

        // 初始化
        onPreExecute();

        sExecutor.execute(MyTask.this);
    }

    private void finish() {
        Log4an.d("zyc.MyTask", "do finish");

        onPostExecute();
        mStatus = Status.FINISHED;
    }

    private static class InternalHandler extends Handler {

        @Override
        public void handleMessage(Message msg) {
            MyTask result = (MyTask) msg.obj;

            Log4an.d("zyc.MyTask", "do Handler");

            switch (msg.what) {
                case MESSAGE_POST_RESULT:

                    Log4an.d("zyc.MyTask", "start finish");

                    result.finish();
                    break;
            }
        }
    }
}
